﻿// -------------------------------------------------------------------------------------------------------------------------------
// <copyright file="TestMultiplyDenseVector.cs" company="Exul">
//     Copyright (c) Exul. All rights reserved.
// </copyright>
// <author>
//     Exul
// </author>
// -------------------------------------------------------------------------------------------------------------------------------

namespace ExulLibrary.Mathematics.LinearAlgebra.Sequential.Tests.DenseSymmetricMatrixTest.DoubleExtensions
{
    #region Usings

    using System;

    using ExulLibrary.Mathematics.LinearAlgebra.Sequential.DoubleExtensions;

    using NUnit.Framework;

    using Extensions = ExulLibrary.Mathematics.LinearAlgebra.Sequential.DoubleExtensions.DenseSymmetricMatrixExtensions;

    #endregion

    /// <summary>
    ///     Test suite for
    ///     <see cref="Extensions.Multiply(DenseSymmetricMatrix{double},DenseVector{double},DenseVector{double})"/>.
    /// </summary>
    [TestFixture]
    [Category("ExulLibrary.Mathematics.LinearAlgebra.Sequential.DoubleExtensions.DenseSymmetricMatrixExtensions")]
    public sealed class TestMultiplyDenseVector
    {
        /// <summary>
        ///     Tests the method when multiplier and result have the same size as corresponding matrix dimension.
        /// </summary>
        [Test]
        public void WhenMultiplierAndResultHaveTheSameSizeAsMatrixDimension()
        {
            // Arrange
            // Matrix:
            // 1 2
            // 2 3
            var multiplicandData = new double[] { 1, 2, 3 };
            var multiplicand = new DenseSymmetricMatrix<double>(multiplicandData);
            var multiplier = new DenseVector<double>(new double[] { 10, 100 });
            var result = new DenseVector<double>(2);
            var expectedResult = new double[] { 210, 320 };

            // Act
            multiplicand.Multiply(multiplier, result);

            // Assert
            Assert.That(result.Values, Is.EquivalentTo(expectedResult));
        }

        /// <summary>
        ///     Tests the method when multiplier has less size than corresponding matrix dimension.
        /// </summary>
        [Test]
        public void WhenMultiplierHasLessSizeThanMatrixDimension()
        {
            // Arrange
            // Matrix:
            // 1 2
            // 2 3
            var multiplicandData = new double[] { 1, 2, 3 };
            var multiplicand = new DenseSymmetricMatrix<double>(multiplicandData);
            var multiplier = new DenseVector<double>(new double[] { 10 });
            var result = new DenseVector<double>(2);
            var expectedResult = new double[] { 10, 0 };

            // Act
            multiplicand.Multiply(multiplier, result);

            // Assert
            Assert.That(result.Values, Is.EquivalentTo(expectedResult));
        }

        /// <summary>
        ///     Tests the method when multiplier has greater size than corresponding matrix dimension.
        /// </summary>
        [Test]
        public void WhenMultiplierHasGreaterSizeThanMatrixDimension()
        {
            // Arrange
            // Matrix:
            // 1 2
            // 2 3
            var multiplicandData = new double[] { 1, 2, 3 };
            var multiplicand = new DenseSymmetricMatrix<double>(multiplicandData);
            var multiplier = new DenseVector<double>(new double[] { 10, 100, 1000 });
            var result = new DenseVector<double>(2);
            var expectedResult = new double[] { 210, 320 };

            // Act
            multiplicand.Multiply(multiplier, result);

            // Assert
            Assert.That(result.Values, Is.EquivalentTo(expectedResult));
        }

        /// <summary>
        ///     Tests the method when result has less size than corresponding matrix dimension.
        /// </summary>
        [Test]
        public void WhenResultHasLessSizeThanMatrixDimension()
        {
            // Arrange
            // Matrix:
            // 1 2
            // 2 3
            var multiplicandData = new double[] { 1, 2, 3 };
            var multiplicand = new DenseSymmetricMatrix<double>(multiplicandData);
            var multiplier = new DenseVector<double>(new double[] { 10, 100 });
            var result = new DenseVector<double>(1);
            var expectedResult = new double[] { 10 };

            // Act
            multiplicand.Multiply(multiplier, result);

            // Assert
            Assert.That(result.Values, Is.EquivalentTo(expectedResult));
        }

        /// <summary>
        ///     Tests the method when result has greater size than corresponding matrix dimension.
        /// </summary>
        [Test]
        public void WhenResultHasGreaterSizeThanMatrixDimension()
        {
            // Arrange
            // Matrix:
            // 1 2
            // 2 3
            var multiplicandData = new double[] { 1, 2, 3 };
            var multiplicand = new DenseSymmetricMatrix<double>(multiplicandData);
            var multiplier = new DenseVector<double>(new double[] { 10, 100 });
            var result = new DenseVector<double>(3);
            var expectedResult = new double[] { 210, 320, 0 };

            // Act
            multiplicand.Multiply(multiplier, result);

            // Assert
            Assert.That(result.Values, Is.EquivalentTo(expectedResult));
        }

#if SAFE

        /// <summary>
        ///     Tests the method when multiplicand is <see langword="null"/>.
        /// </summary>
        [Test]
        public void WhenMultiplicandIsNull()
        {
            // Arrange
            var multiplier = new DenseVector<double>(2);
            var result = new DenseVector<double>(2);

            // Act and Assert
            Assert.That(
                () => DenseSymmetricMatrixExtensions.Multiply(null, multiplier, result),
                Throws.TypeOf<ArgumentNullException>().With.Property("ParamName").EqualTo("multiplicand"));
        }

        /// <summary>
        ///     Tests the method when multiplier is <see langword="null"/>.
        /// </summary>
        [Test]
        public void WhenMultiplierIsNull()
        {
            // Arrange
            var multiplicand = new DenseSymmetricMatrix<double>(2);
            var result = new DenseVector<double>(3);

            // Act and Assert
            Assert.That(
                () => multiplicand.Multiply(null, result),
                Throws.TypeOf<ArgumentNullException>().With.Property("ParamName").EqualTo("multiplier"));
        }

        /// <summary>
        ///     Tests the method when result is <see langword="null"/>.
        /// </summary>
        [Test]
        public void WhenResultIsNull()
        {
            // Arrange
            var multiplicand = new DenseSymmetricMatrix<double>(2);
            var multiplier = new DenseVector<double>(3);

            // Act and Assert
            Assert.That(
                () => multiplicand.Multiply(multiplier, null),
                Throws.TypeOf<ArgumentNullException>().With.Property("ParamName").EqualTo("result"));
        }

#endif
    }
}